"""
日志核心配置模块

提供灵活的日志记录器配置功能，支持：
- 多种日志轮转策略(大小/时间/混合)
- 异步日志记录
- 线程安全实现
- 自定义日志格式和级别
- 文件和控制台输出

注意：
1. 在多线程环境中使用异步日志(use_async=True)可获得最佳性能
2. 生产环境建议使用基于时间的轮转(handler_type='time')
3. 日志文件默认保存在logs目录下
"""

import logging
import logging.handlers
import os
import glob
import queue
import inspect
from threading import Thread
from pathlib import Path
import weakref
from .handlers import CustomRotatingFileHandler, CustomTimedRotatingFileHandler


# 日志记录器缓存，使用弱引用避免内存泄漏
_logger_cache = weakref.WeakValueDictionary()

def setup_logger(
    level=logging.INFO,
    log_format=None,
    show_file_line=True,
    log_file=None,
    filemode='a',
    use_async=False,
    buffer_size=0,
    max_bytes=10 * 1024 * 1024,
    backup_count=15,
    delay=False,
    module_name=None,
    when='D',
    backup_when=15,
    handler_type='time',
    console=False,
    console_level=None,
    share_file=False,
    base_dir='logs'
):
    """
    配置并返回一个日志记录器

    参数:
        level (int): 日志级别(DEBUG/INFO/WARNING/ERROR/CRITICAL)
        log_format (str): 自定义日志格式字符串
        show_file_line (bool): 是否显示文件名和行号
        log_file (str): 日志文件路径，None则自动生成
        filemode (str): 文件打开模式('a'追加/'w'覆盖)
        use_async (bool): 是否使用异步日志(提升性能)
        buffer_size (int): 内存缓冲区大小(0表示禁用)
        max_bytes (int): 单个日志文件最大字节数(仅handler_type='size'或'both'时有效)
        backup_count (int): 保留的备份文件数量(最少10个)
        delay (bool): 延迟文件打开直到首次写入
        module_name (str): 模块名称(用于自动生成日志文件名)
        when (str): 时间轮转间隔('S'秒/'M'分/'H'时/'D'天)
        backup_when (int): 时间轮转保留的备份天数
        handler_type (str): 处理器类型('size'大小轮转/'time'时间轮转/'both'混合)
        console (bool): 是否输出到控制台
        console_level (int): 控制台日志级别(默认同文件级别)
        share_file (bool): 是否在多个记录器间共享文件处理器
        base_dir (str): 日志文件存储的基本目录，默认为'logs'

    返回:
        logging.Logger: 配置好的日志记录器实例

    示例:
        # 基本配置(时间轮转)
        logger = setup_logger(level=logging.INFO,
                            log_file='app.log',
                            handler_type='time')

        # 高级配置(混合轮转+异步)
        logger = setup_logger(level=logging.DEBUG,
                            show_file_line=True,
                            log_file='debug.log',
                            use_async=True,
                            max_bytes=1048576,
                            backup_count=20,
                            handler_type='both',
                            console=True)
    """
    try:
        # 如果未指定日志文件，则根据模块名和日期生成日志文件路径
        if log_file is None:
            from datetime import datetime
            date_str = datetime.now().strftime('%Y_%m_%d')
            if module_name:
                log_file = f'{base_dir}/{module_name}_{date_str}.log'
            else:
                log_file = f'{base_dir}/app_{date_str}.log'

        # 确保使用绝对路径
        if not os.path.isabs(log_file):
            # 获取当前工作目录
            cwd = os.getcwd()
            log_file = os.path.join(cwd, log_file)

        # 确保日志目录存在
        log_dir = os.path.dirname(log_file)
        os.makedirs(log_dir, exist_ok=True)

        # 设置默认日志格式
        if log_format is None:
            if show_file_line:
                log_format = '%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
            else:
                log_format = '%(asctime)s - %(levelname)s - %(message)s'

        # 创建日志格式
        formatter = logging.Formatter(log_format)

        # 设置日志记录器名称
        logger_name = module_name or __name__

        # 检查缓存中是否已存在相同配置的日志记录器
        cache_key = f"{logger_name}:{log_file}:{level}:{handler_type}"
        if share_file:
            # 如果启用文件共享，则使用文件路径作为缓存键的一部分
            cache_key = f"shared:{log_file}:{level}:{handler_type}"

        if cache_key in _logger_cache:
            return _logger_cache[cache_key]

        # 创建适当的文件处理器
        if handler_type == 'size':
            # 基于大小的日志轮转
            handler = CustomRotatingFileHandler(
                log_file,
                mode=filemode,
                maxBytes=max_bytes,
                backupCount=max(backup_count, 10),  # 最少10个备份文件
                encoding='utf-8',
                delay=delay
            )
        elif handler_type == 'time':
            # 基于时间的日志轮转
            handler = CustomTimedRotatingFileHandler(
                log_file,
                when=when,
                backupCount=max(backup_when, 10),  # 最少10个备份文件
                encoding='utf-8',
                delay=delay
            )
        elif handler_type == 'both':
            # 同时使用基于大小和时间的轮转
            # 创建一个自定义处理器类，继承TimedRotatingFileHandler并添加大小限制
            class SizeTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
                def __init__(self, filename, when='h', interval=1, backupCount=0,
                             encoding=None, delay=False, utc=False, atTime=None,
                             maxBytes=0):
                    super().__init__(filename, when, interval, backupCount,
                                    encoding, delay, utc, atTime)
                    self.maxBytes = maxBytes

                def shouldRollover(self, record):
                    # 检查是否应该基于时间进行轮转
                    time_rollover = super().shouldRollover(record)
                    if time_rollover:
                        return time_rollover
                    # 检查是否应该基于大小进行轮转
                    if self.maxBytes > 0:
                        if self.stream is None:
                            self.stream = self._open()
                        if self.stream.tell() >= self.maxBytes:
                            return 1
                    return 0

            handler = SizeTimedRotatingFileHandler(
                log_file,
                when=when,
                backupCount=backup_when,
                encoding='utf-8',
                delay=delay,
                maxBytes=max_bytes
            )
        else:
            raise ValueError(f"无效的handler_type: {handler_type}。必须是'size', 'time'或'both'")

        handler.setFormatter(formatter)

        # 如果启用控制台输出
        if console:
            console_handler = logging.StreamHandler()
            console_handler.setLevel(console_level or level)
            console_handler.setFormatter(formatter)

        # 如果启用缓冲
        if buffer_size > 0:
            handler = logging.handlers.MemoryHandler(buffer_size, flushLevel=logging.ERROR, target=handler)

        # 创建日志队列和监听器（异步写入）
        if use_async:
            log_queue = queue.Queue()
            queue_handler = logging.handlers.QueueHandler(log_queue)
            listener = logging.handlers.QueueListener(log_queue, handler)
            listener.start()
            handler = queue_handler

        # 创建模块级别日志记录器
        logger = logging.getLogger(logger_name)
        logger.setLevel(level)

        # 清除已有 handler，避免重复添加
        for h in logger.handlers[:]:
            logger.removeHandler(h)

        # 添加文件处理器
        logger.addHandler(handler)

        # 添加控制台处理器（如果启用）
        if console:
            logger.addHandler(console_handler)

        # 保存 listener 以便在程序退出时停止
        if use_async:
            logger.listener = listener

        # 将日志记录器添加到缓存
        _logger_cache[cache_key] = logger

        return logger
    except Exception as e:
        # 记录异常信息并重新抛出
        import traceback
        error_msg = f"创建日志记录器时发生错误: {str(e)}"
        print(error_msg)
        print(traceback.format_exc())
        raise RuntimeError(error_msg) from e